// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "SQLReplaceStatement.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/listTran.h"
#include "SQLExprTableSource.h"
#include "../expr/SQLQueryExpr.h"
#include "SQLInsertStatement.h"
#include "SQLAssignItem.h"

SQLReplaceStatement::SQLReplaceStatement()
{
  columns = std::make_shared<std::list<SQLExpr_ptr>>();
  valuesList = std::make_shared<std::list<SQLInsertStatement_ValuesClause_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  partitions = std::make_shared<std::list<SQLAssignItem_ptr>>();
}

SQLName_ptr SQLReplaceStatement::getTableName()
{
  if (tableSource == nullptr)
  {
    return nullptr;
  }

  return std::dynamic_pointer_cast<SQLName>(tableSource->getExpr());
}

void SQLReplaceStatement::setTableName(SQLName_ptr tableName)
{
  this->setTableSource(SQLExprTableSource_ptr(new SQLExprTableSource(tableName)));
}

SQLExprTableSource_ptr SQLReplaceStatement::getTableSource()
{
  return tableSource;
}

void SQLReplaceStatement::setTableSource(SQLExprTableSource_ptr tableSource)
{
  if (tableSource != nullptr)
  {
    tableSource->setParent(SharedObject(SQLReplaceStatement));
  }
  this->tableSource = tableSource;
}

SQLExpr_list_ptr SQLReplaceStatement::getColumns()
{
  return columns;
}

void SQLReplaceStatement::addColumn(SQLExpr_ptr column)
{
  if (column != nullptr)
  {
    column->setParent(SharedObject(SQLReplaceStatement));
  }
  this->columns->push_back(column);
}

BOOL_ptr SQLReplaceStatement::isLowPriority()
{
  return lowPriority;
}

void SQLReplaceStatement::setLowPriority(BOOL_ptr lowPriority)
{
  this->lowPriority = lowPriority;
}

BOOL_ptr SQLReplaceStatement::isDelayed()
{
  return delayed;
}

void SQLReplaceStatement::setDelayed(BOOL_ptr delayed)
{
  this->delayed = delayed;
}

SQLQueryExpr_ptr SQLReplaceStatement::getQuery()
{
  return query;
}

void SQLReplaceStatement::setQuery(SQLQueryExpr_ptr query)
{
  if (query != nullptr)
  {
    query->setParent(SharedObject(SQLReplaceStatement));
  }
  this->query = query;
}

SQLInsertStatement_ValuesClause_list_ptr SQLReplaceStatement::getValuesList()
{
  return valuesList;
}

// @Override
SQLObject_ptr SQLReplaceStatement::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLReplaceStatement>(new SQLReplaceStatement());
  std::shared_ptr<SQLReplaceStatement> x = std::dynamic_pointer_cast<SQLReplaceStatement>(clone_tmp);
  // SQLReplaceStatement x = new SQLReplaceStatement();
  x->setDbType(this->dbType);

  if (headHints != nullptr)
  {
    for (SQLCommentHint_ptr h : *headHints)
    {
      SQLCommentHint_ptr clone = std::dynamic_pointer_cast<SQLCommentHint>(h->clone());
      clone->SQLObjectImpl::setParent(x);
      x->headHints->push_back(clone);
    }
  }

  if (hints != nullptr && !hints->empty())
  {
    for (SQLCommentHint_ptr h : *hints)
    {
      SQLCommentHint_ptr clone = std::dynamic_pointer_cast<SQLCommentHint>(h->clone());
      clone->SQLObjectImpl::setParent(x);
      x->getHints()->push_back(clone);
    }
  }

  x->lowPriority = this->lowPriority;
  x->delayed = this->delayed;

  if (this->tableSource != nullptr)
  {
    x->tableSource = std::dynamic_pointer_cast<SQLExprTableSource>(this->tableSource->clone());
  }

  for (SQLInsertStatement_ValuesClause_ptr clause : *valuesList)
  {
    x->getValuesList()->push_back(std::dynamic_pointer_cast<SQLInsertStatement_ValuesClause>(clause->clone()));
  }

  for (SQLExpr_ptr column : *columns)
  {
    x->addColumn(std::dynamic_pointer_cast<SQLExpr>(column->clone()));
  }

  if (query != nullptr)
  {
    x->query = std::dynamic_pointer_cast<SQLQueryExpr>(this->query->clone());
  }

  if (partitions != nullptr)
  {
    for (SQLAssignItem_ptr partition : *partitions)
    {
      x->addPartition(std::dynamic_pointer_cast<SQLAssignItem>(partition->clone()));
    }
  }

  return x;
}

// @Override
void SQLReplaceStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLReplaceStatement)))
  {
    acceptChild(visitor, tableSource);
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(columns);
    acceptChild(visitor, tmp1);
    SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLInsertStatement_ValuesClause, SQLObject>(valuesList);
    acceptChild(visitor, tmp2);
    acceptChild(visitor, query);
  }
  visitor->endVisit(SharedObject(SQLReplaceStatement));
}

int SQLReplaceStatement::getHintsSize()
{
  if (hints == nullptr)
  {
    return 0;
  }

  return hints->size();
}

SQLCommentHint_list_ptr SQLReplaceStatement::getHints()
{
  if (hints == nullptr)
  {
    hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
    ;
  }
  return hints;
}

void SQLReplaceStatement::setHints(SQLCommentHint_list_ptr hints)
{
  this->hints = hints;
}

void SQLReplaceStatement::addPartition(SQLAssignItem_ptr partition)
{
  if (partition != nullptr)
  {
    partition->setParent(SharedObject(SQLReplaceStatement));
  }

  if (partitions == nullptr)
  {
    partitions = std::make_shared<std::list<SQLAssignItem_ptr>>();
  }

  this->partitions->push_back(partition);
}

SQLAssignItem_list_ptr SQLReplaceStatement::getPartitions()
{
  return partitions;
}
